/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS  
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). 
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.  
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR  
 * COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND  
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE  
 * MAY BE CONSIDERED TO BE A CONTRACT,
 * THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED 
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 */
package lineage.database.tables;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;

import lineage.database.L1AbstractDatabase;
import lineage.database.tables.bean.L1Exp;
import lineage.util.PerformanceTimer;
import lineage.util.Util;
import lineage.util.collections.Maps;

/**
 * 经验值资料表.
 * 
 * @version 2014年3月22日上午11:22:16
 * @author jrwz
 */
public final class ExpTable extends L1AbstractDatabase {
    private static final Map<Integer, L1Exp> list = Maps.newHashMap();
    /** 最高等级. */
    private int maxLevel;
    /** 最高经验值. */
    private long maxExp;

    /**
     * 静态初始化器，由JVM来保证线程安全.
     */
    private static class Holder {
        static ExpTable instance = new ExpTable();
    }

    /**
     * 取得该类的实例.
     */
    public static ExpTable getInstance() {
        return Holder.instance;
    }

    private ExpTable() {
        batch("SELECT * FROM `exp`");
    }

    @Override
    public void fillTable(final ResultSet rs) throws SQLException {
        final PerformanceTimer timer = new PerformanceTimer();
        final StringBuilder sb = new StringBuilder();
        sb.append("加载数据库：经验值");

        while (rs.next()) {
            L1Exp l1exp = new L1Exp();
            final int level = rs.getInt("level");
            final long exp = rs.getLong("exp");
            final double expPenalty = rs.getDouble("exp_penalty");
            if (level > maxLevel) {
                setMaxLevel(level);
            }
            if (exp > maxExp) {
                setMaxExp(exp);
            }
            l1exp.setLevel(level);
            l1exp.setExp(exp);
            l1exp.setExpPenalty(expPenalty);
            put(l1exp);
        }
        maxLevel -= 1;

        sb.append("(");
        sb.append(list.size());
        sb.append(")\t耗时 ");
        sb.append(timer.elapsedTimeMillis());
        sb.append(" 毫秒");
        Util.message(Util.SYSTEM_MESSAGE, sb.toString());
    }

    /**
     * 取得指定等级所需要的经验值.
     * 
     * @param level
     *            - 等级
     * @return 所需要的经验值(如果没找到则返回0)
     */
    public long getExpByLevel(final int level) {
        final L1Exp l1exp = list.get(Integer.valueOf(level - 1));
        long exp = 0L;
        if (l1exp != null) {
            exp = l1exp.getExp();
        }
        return exp;
    }

    /**
     * 取得下一个等级需要的经验值.
     * 
     * @param level
     *            - 等级
     * @return 所需要的经验值
     */
    public long getNeedExpNextLevel(final int level) {
        return getExpByLevel(level + 1) - getExpByLevel(level);
    }

    /**
     * 累积经验值对应的等级.
     * 
     * @param exp
     *            - 累积的经验值
     * @return 对应的等级
     */
    public int getLevelByExp(final long exp) {
        int level = 1;
        for (Integer integer : list.keySet()) {
            if (integer == 0) {
                continue;
            }
            L1Exp up = list.get(integer);
            L1Exp dn = list.get(integer - 1);
            final long upe = up.getExp();
            final long dne = dn.getExp();
            if ((exp >= dne) && (exp < upe)) {
                level = integer;
            }
        }
        return Math.min(level, maxLevel);
    }

    /**
     * 取得目前等级可取回的经验值.
     * 
     * @param level
     *            - 等级
     * @return 经验值(如果没找到则返回0)
     */
    public double getPenaltyRate(final int level) {
        final L1Exp l1exp = list.get(Integer.valueOf(level));
        double expPenalty = 1.0D;
        if (l1exp != null) {
            expPenalty = 1.0D / l1exp.getExpPenalty();
        }
        return expPenalty;
    }

    /**
     * 将新元素加入集合列表.
     * 
     * @param exp
     *            - L1Exp对象
     */
    public void put(final L1Exp exp) {
        list.put(Integer.valueOf(exp.getLevel()), exp);
    }

    /**
     * 取得最高等级.
     * 
     * @return 最高等级
     */
    public int getMaxLevel() {
        return maxLevel;
    }

    /**
     * 设置最高等级.
     * 
     * @param maxLevel
     *            - 要设置最高等级
     */
    public void setMaxLevel(int maxLevel) {
        this.maxLevel = maxLevel;
    }

    /**
     * 取得最高经验值.
     * 
     * @return 最高经验值
     */
    public long getMaxExp() {
        return maxExp;
    }

    /**
     * 设置最高经验值.
     * 
     * @param maxExp
     *            - 要设置的最高经验值
     */
    public void setMaxExp(long maxExp) {
        this.maxExp = maxExp;
    }
}
